///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2007-2009 ILOG, S.A.
//  All Rights Reserved.
//  The following is ILOG Source Code.  No modifications may be made to the  
//  ILOG Source Code.  Any usage of the ILOG Source Code is subject to 
//  the terms and conditions of the ILOG End User License Agreement   
//  applicable to this ILOG software product.
//
///////////////////////////////////////////////////////////////////////////////

package ilog.gauges.gaugesClasses
{
  import flash.events.EventDispatcher;
  
  import mx.collections.ArrayCollection;

  /**
   *  The <code>ScaleBase</code> class serves as a base class
   *  for the various scale types supported in ILOG Elixir. 
   *  Scales are responsible for ticks generation and various
   *  data transform operations depending on the type of gauge.
   *  Circular scales map a value to an angle, whereas
   *  rectangular scales map a value to a pixel position.
   *  Circular scales implement <code>ICircularScale</code>. Rectangular 
   *  scales implement <code>IRectangularScale</code>.
   *  <p>
   *  Visual elements can register to a scale using the
   *  <code>registerElement(element:GaugeElement)</code> method.
   *  The scale will notify the visual elements
   *  when its relevant values have changed.
   *  </p>
   * 
   *  @mxml
   *  <p>The <code>&lt;ScaleBase&gt;</code> tag inherits all the
   *  properties of its parent classes and adds the following properties:</p>
   *  
   *  <pre>
   *  &lt;ScaleBase
   *    <strong>Properties</strong>  
   *    majorTickItems="[]"
   *    minorTickItems="[]" 
   * /&gt;
   *  </pre>
   * 
   */
  public class ScaleBase extends EventDispatcher implements IScale
  {
    /**
     * Constructor
     */    
    public function ScaleBase()
    {
      super();
      _elements = new ArrayCollection();
    }
    
    private var _majorTicksDirty:Boolean = true;
    private var _minorTicksDirty:Boolean = true;
    
    /**
     * Storage for the majorTickItems property.
     */
    private var _majorTickItems:Array = [];

    /**
     * @copy ilog.gauges.gaugesClasses.IScale#majorTickItems
     */
    public function get majorTickItems():Array
    {
      if (_majorTicksDirty) {
        _majorTickItems = buildMajorTickItems();
        _majorTicksDirty = false;
      }
      return _majorTickItems;
    }

    /**
     * Storage for the minorTickItems property.
     */
    private var _minorTickItems:Array = [];

    /**
     * @copy ilog.gauges.gaugesClasses.IScale#minorTickItems
     */
    public function get minorTickItems():Array
    {
      if (_minorTicksDirty) {        
        _minorTickItems = buildMinorTickItems();
        _minorTicksDirty = false;
      }
      return _minorTickItems;
    }
    
    /**
     * Generates the major ticks of the scale.
     * Subclasses must implement this function.
     * @return An array of <code>TickItem</code> instances representing the major
     * ticks. 
     */
    protected function buildMajorTickItems():Array
    {
      return null;
    }

    /**
     * Generates the minor ticks of the scale.
     * Subclasses must implement this function.
     * Category scales do not use minor ticks.
     * @return An array of <code>TickItem</code> instances representing the minor
     * ticks. 
     */
    protected function buildMinorTickItems():Array
    {
      return null;
    }

    /**
     * @copy ilog.gauges.gaugesClasses.IScale#invalidateTicks()
     */
    public function invalidateTicks():void
    {
      _majorTicksDirty = true;
      _minorTicksDirty = true;
      invalidateElements();
    }

    /**
     * @private
     */    
    private var _elements:ArrayCollection;


    /**
     * Contains the visual elements that need this scale to render themselves.
     * 
     */
    public function get elements():ArrayCollection
    {
      return _elements;
    }

    /**
     * @copy ilog.gauges.gaugesClasses.IScale#registerElement()
     */
    public function registerElement(element:GaugeElement):void
    {
      if (! _elements.contains(element)) {
        _elements.addItem(element);
        // first time he see us, invalidate it
        // TODO: check why this invalidateProperties is here (CRSR caching?)
        // and remove it
        element.invalidateProperties();
        element.invalidateDisplayList();
      }
    }

    /**
     * @copy ilog.gauges.gaugesClasses.IScale#unregisterElement()
     */
    public function unregisterElement(element:GaugeElement):void
    {
      if (_elements.contains(element))
        _elements.removeItemAt(_elements.getItemIndex(element));
    }

    /**
     * @copy ilog.gauges.gaugesClasses.IScale#invalidateElements()
     */
    public function invalidateElements():void
    {
      for each (var element:GaugeElement in _elements) {
        element.invalidateDisplayList();
      }
    }          
  }
}
